﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Recorder.cs" company="">
//   
// </copyright>
// <summary>
//   The recorder.
// </summary>
// --------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Timers;

namespace Systemathics.FrameWork
{
    public sealed class Recorder
    {
        private readonly List<Guid> Instruments;
        private readonly Dictionary<Guid, Instrument> InstrumentsToRecord;
        private readonly DataService provider;
        private DateTime StopDateTime;
        private readonly Timer TimerStart;
        private readonly Timer TimerStop;
        private readonly Dictionary<Guid, bool> OpenCloseStatus;
        private readonly DataManager DataManager;
        private DateTime StartDateTime;
        private DateTime EffectiveStartDateTime;

        public ConnectionStatus Status { get; private set; }
        public event EventHandler<FireMessageEventArgs> RecorderStatus;

        #region Constructor

        public Recorder(DataService provider, DateTime Start, DateTime Stop, List<Guid> Instrs)
        {
            if (Instrs.Count > 0)
            {
                InstrumentsToRecord = new Dictionary<Guid, Instrument>();
                OpenCloseStatus = new Dictionary<Guid, bool>();
                foreach (Guid Guid in Instrs)
                    OpenCloseStatus[Guid] = false;

                StartDateTime = Start;
                StopDateTime = Stop;
                Instruments = Instrs;
                DataManager = new DataManager(Instruments.ToArray());
                this.provider = provider;
                provider.EmitNewTrade += EmitNewTrade;
                provider.EmitNewMarketData += EmitNewMarketData;
                provider.EmitNewBlotter += EmitNewBlotter;
                TimerStart = new Timer();
                TimerStart.Elapsed += TimerStartElapsed;
                TimerStop = new Timer();
                TimerStop.Elapsed += TimerStopElapsed;
            }
            Status = ConnectionStatus.Disconnected;
        }

        #endregion Constructor

        #region Recorder Methods

        private void EmitNewTrade(object sender, Trade e)
        {
            if (Instruments.Contains(e.Id))
                DataManager.Write(e.Clone() as Trade);
        }
        private void EmitNewBlotter(object sender, Blotter e)
        {
            if (Instruments.Contains(e.Id))
                DataManager.Write(e.Clone() as Blotter);
        }
        private void EmitNewMarketData(object sender, MarketData e)
        {
            if (Instruments.Contains(e.Id) && !OpenCloseStatus[e.Id])
            {
                OpenCloseStatus[e.Id] = true;
                DataManager.Write(e);
            }
        }
        private void TimerStartElapsed(object sender, ElapsedEventArgs e)
        {
            TimerStart.Stop();
            Start();
            var ticks = StopDateTime - EffectiveStartDateTime;
            TimerStop.Interval = ticks.Duration().TotalMilliseconds;
            TimerStop.Start();
        }
        private void TimerStopElapsed(object sender, ElapsedEventArgs e)
        {
            Stop();
            TimerStop.Stop();
            Start();
        }
        public void Start()
        {
            if (Time.Now >= StartDateTime && Time.Now <= StopDateTime)
            {
                foreach (var guid in Instruments.ToArray())
                {
                    InstrumentsToRecord[guid] = new Instrument(guid);
                    provider.Suscribe(InstrumentsToRecord[guid]);
                }

                EffectiveStartDateTime = Time.Now;
                var ticks1 = StopDateTime - EffectiveStartDateTime;
                TimerStop.Interval = ticks1.Duration().TotalMilliseconds;
                TimerStop.Start();
                RecorderStatus(this, new FireMessageEventArgs(ConnectionStatus.Connected, Time.Now.TimeOfDay));
            }
            else if (Time.Now.TimeOfDay < StartDateTime.TimeOfDay)
            {
                var ticks2 = StartDateTime.TimeOfDay - Time.Now.TimeOfDay;
                TimerStart.Interval = ticks2.Duration().TotalMilliseconds;
                EffectiveStartDateTime = StartDateTime;
                TimerStart.Start();
            }
            else if (Time.Now.TimeOfDay > StopDateTime.TimeOfDay)
            {
                StartDateTime = StartDateTime.AddDays(1);
                var ticks3 = StartDateTime - StopDateTime;
                StopDateTime = StopDateTime.AddDays(1);
                TimerStart.Interval = ticks3.Duration().TotalMilliseconds;
                EffectiveStartDateTime = StartDateTime;
                TimerStart.Start();
            }
            
            EffectiveStartDateTime = Time.Now;
            var ticks = StopDateTime - EffectiveStartDateTime;
            TimerStop.Interval = ticks.Duration().TotalMilliseconds;
            TimerStop.Start();
            Status = ConnectionStatus.Connected;
            RecorderStatus(this, new FireMessageEventArgs(ConnectionStatus.Connected, Time.Now.TimeOfDay));
        }
        public void Stop()
        {
            if (Instruments != null && DataManager != null)
            {
                foreach (var guid in Instruments.ToArray())
                    provider.Unsubscribe(InstrumentsToRecord[guid]);

                provider.EmitNewTrade -= EmitNewTrade;
                provider.EmitNewBlotter -= EmitNewBlotter;
                provider.EmitNewMarketData -= EmitNewMarketData;
                if (DataManager.isEnabled)
                    DataManager.Close();
                Status = ConnectionStatus.Disconnected;
                RecorderStatus(this, new FireMessageEventArgs(ConnectionStatus.Disconnected, Time.Now.TimeOfDay));
            }
        }

        #endregion Recorder Methods
    }
} 